8191437: AOT doesn't work easily after thread local handshakes
authordlong
Thu, 30 Nov 2017 10:40:48 -0800
changeset 48172 e26fc5201707
parent 48171 7ad2d33a0f05
child 48173 cb63f08dad03
8191437: AOT doesn't work easily after thread local handshakes Reviewed-by: kvn, rehn, aph
src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp
src/hotspot/share/aot/aotCodeHeap.cpp
src/hotspot/share/aot/aotCodeHeap.hpp
src/hotspot/share/jvmci/vmStructs_jvmci.cpp
src/hotspot/share/runtime/arguments.cpp
src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.cpp
src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java
src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotEpilogueOp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotNodeLIRBuilder.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotReturnOp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSafepointOp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotReturnOp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotReturnOp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotSafepointOp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java
test/hotspot/jtreg/runtime/handshake/HandshakeTransitionTest.java
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp	Thu Nov 30 10:40:48 2017 -0800
@@ -3388,26 +3388,29 @@
   // No exception case
   __ bind(noException);
 
-  Label no_adjust, bail;
+  Label no_adjust, bail, no_prefix;
   if (SafepointMechanism::uses_thread_local_poll() && !cause_return) {
     // If our stashed return pc was modified by the runtime we avoid touching it
     __ cmpptr(rbx, Address(rbp, wordSize));
     __ jccb(Assembler::notEqual, no_adjust);
 
-#ifdef ASSERT
     // Verify the correct encoding of the poll we're about to skip.
     // See NativeInstruction::is_safepoint_poll()
     __ cmpb(Address(rbx, 0), NativeTstRegMem::instruction_rex_b_prefix);
-    __ jcc(Assembler::notEqual, bail);
-    __ cmpb(Address(rbx, 1), NativeTstRegMem::instruction_code_memXregl);
+    __ jcc(Assembler::notEqual, no_prefix);
+    __ addptr(rbx, 1);
+    __ bind(no_prefix);
+#ifdef ASSERT
+    __ cmpb(Address(rbx, 0), NativeTstRegMem::instruction_code_memXregl);
     __ jcc(Assembler::notEqual, bail);
     // Mask out the modrm bits
-    __ testb(Address(rbx, 2), NativeTstRegMem::modrm_mask);
+    __ testb(Address(rbx, 1), NativeTstRegMem::modrm_mask);
     // rax encodes to 0, so if the bits are nonzero it's incorrect
     __ jcc(Assembler::notZero, bail);
 #endif
     // Adjust return pc forward to step over the safepoint poll instruction
-    __ addptr(Address(rbp, wordSize), 3);
+    __ addptr(rbx, 2);
+    __ movptr(Address(rbp, wordSize), rbx);
   }
 
   __ bind(no_adjust);
--- a/src/hotspot/share/aot/aotCodeHeap.cpp	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/hotspot/share/aot/aotCodeHeap.cpp	Thu Nov 30 10:40:48 2017 -0800
@@ -167,6 +167,7 @@
   verify_flag(_config->_compactFields, CompactFields, "CompactFields");
   verify_flag(_config->_enableContended, EnableContended, "EnableContended");
   verify_flag(_config->_restrictContended, RestrictContended, "RestrictContended");
+  verify_flag(_config->_threadLocalHandshakes, ThreadLocalHandshakes, "ThreadLocalHandshakes");
 
   if (!TieredCompilation && _config->_tieredAOT) {
     handle_config_error("Shared file %s error: Expected to run with tiered compilation on", _name);
--- a/src/hotspot/share/aot/aotCodeHeap.hpp	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/hotspot/share/aot/aotCodeHeap.hpp	Thu Nov 30 10:40:48 2017 -0800
@@ -92,7 +92,7 @@
 } AOTHeader;
 
 typedef struct {
-  enum { CONFIG_SIZE = 7 * jintSize + 11 };
+  enum { CONFIG_SIZE = 7 * jintSize + 12 };
   // 7 int values
   int _config_size;
   int _narrowOopShift;
@@ -101,7 +101,7 @@
   int _fieldsAllocationStyle;
   int _objectAlignment;
   int _codeSegmentSize;
-  // byte[11] array map to boolean values here
+  // byte[12] array map to boolean values here
   bool _debug_VM;
   bool _useCompressedOops;
   bool _useCompressedClassPointers;
@@ -113,6 +113,7 @@
   bool _enableContended;
   bool _restrictContended;
   bool _omitAssertions;
+  bool _threadLocalHandshakes;
 } AOTConfiguration;
 
 class AOTLib : public CHeapObj<mtCode> {
--- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp	Thu Nov 30 10:40:48 2017 -0800
@@ -317,6 +317,7 @@
                                                                                                                                      \
   nonstatic_field(Thread,                   _tlab,                                            ThreadLocalAllocBuffer)                \
   nonstatic_field(Thread,                   _allocated_bytes,                                 jlong)                                 \
+  nonstatic_field(Thread,                   _polling_page,                                    address)                               \
                                                                                                                                      \
   nonstatic_field(ThreadLocalAllocBuffer,   _start,                                           HeapWord*)                             \
   nonstatic_field(ThreadLocalAllocBuffer,   _top,                                             HeapWord*)                             \
--- a/src/hotspot/share/runtime/arguments.cpp	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/hotspot/share/runtime/arguments.cpp	Thu Nov 30 10:40:48 2017 -0800
@@ -4397,26 +4397,7 @@
   }
 #endif
 
-  bool aot_enabled = UseAOT && AOTLibrary != NULL;
-  bool jvmci_enabled = NOT_JVMCI(false) JVMCI_ONLY(EnableJVMCI || UseJVMCICompiler);
-  bool handshakes_supported = SafepointMechanism::supports_thread_local_poll() && !aot_enabled && !jvmci_enabled && ThreadLocalHandshakes;
   // ThreadLocalHandshakesConstraintFunc handles the constraints.
-  // Here we try to figure out if a mutual exclusive option have been set that conflict with a default.
-  if (handshakes_supported) {
-    FLAG_SET_DEFAULT(UseAOT, false); // Clear the AOT flag to make sure it doesn't try to initialize.
-  } else {
-    if (FLAG_IS_DEFAULT(ThreadLocalHandshakes) && ThreadLocalHandshakes) {
-      if (aot_enabled) {
-        // If user enabled AOT but ThreadLocalHandshakes is at default set it to false.
-        log_debug(ergo)("Disabling ThreadLocalHandshakes for UseAOT.");
-        FLAG_SET_DEFAULT(ThreadLocalHandshakes, false);
-      } else if (jvmci_enabled){
-        // If user enabled JVMCI but ThreadLocalHandshakes is at default set it to false.
-        log_debug(ergo)("Disabling ThreadLocalHandshakes for EnableJVMCI/UseJVMCICompiler.");
-        FLAG_SET_DEFAULT(ThreadLocalHandshakes, false);
-      }
-    }
-  }
   if (FLAG_IS_DEFAULT(ThreadLocalHandshakes) || !SafepointMechanism::supports_thread_local_poll()) {
     log_debug(ergo)("ThreadLocalHandshakes %s", ThreadLocalHandshakes ? "enabled." : "disabled.");
   } else {
--- a/src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.cpp	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/hotspot/share/runtime/commandLineFlagConstraintsRuntime.cpp	Thu Nov 30 10:40:48 2017 -0800
@@ -138,10 +138,6 @@
       CommandLineError::print(verbose, "ThreadLocalHandshakes not yet supported on this platform\n");
       return Flag::VIOLATES_CONSTRAINT;
     }
-    if (UseAOT JVMCI_ONLY(|| EnableJVMCI || UseJVMCICompiler)) {
-      CommandLineError::print(verbose, "ThreadLocalHandshakes not yet supported in combination with AOT or JVMCI\n");
-      return Flag::VIOLATES_CONSTRAINT;
-    }
   }
   return Flag::SUCCESS;
 }
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java	Thu Nov 30 10:40:48 2017 -0800
@@ -65,6 +65,8 @@
 
     private final int codeEntryAlignment;
 
+    private final boolean threadLocalHandshakes;
+
     /**
      * Container holding code bits and any other related information.
      */
@@ -279,6 +281,8 @@
 
         this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment;
 
+        this.threadLocalHandshakes = graalHotSpotVMConfig.threadLocalHandshakes;
+
         // Section unique name is limited to 8 characters due to limitation on Windows.
         // Name could be longer but only first 8 characters are stored on Windows.
 
@@ -323,7 +327,8 @@
                                    TieredAOT.getValue(graalOptions),
                                    graalHotSpotVMConfig.enableContended,
                                    graalHotSpotVMConfig.restrictContended,
-                                   graphBuilderConfig.omitAssertions()
+                                   graphBuilderConfig.omitAssertions(),
+                                   graalHotSpotVMConfig.threadLocalHandshakes
         };
 
         int[] intFlags         = { graalHotSpotVMConfig.getOopEncoding().getShift(),
@@ -434,6 +439,11 @@
         return codeEntryAlignment;
     }
 
+    public boolean getThreadLocalHandshakes() {
+        return threadLocalHandshakes;
+    }
+
+
     /**
      * Gets the global AOT symbol associated with the function name.
      *
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java	Thu Nov 30 10:40:48 2017 -0800
@@ -45,6 +45,7 @@
      * @param methodInfo compiled method info
      * @param mark mark being processed
      */
+    @SuppressWarnings("fallthrough")
     void process(CompiledMethodInfo methodInfo, Mark mark) {
         MarkId markId = MarkId.getEnum((int) mark.id);
         switch (markId) {
@@ -53,6 +54,11 @@
                 break;
             case POLL_FAR:
             case POLL_RETURN_FAR:
+                if (binaryContainer.getThreadLocalHandshakes()) {
+                    // skip relocation
+                    break;
+                }
+                // fallthrough
             case CARD_TABLE_ADDRESS:
             case HEAP_TOP_ADDRESS:
             case HEAP_END_ADDRESS:
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotEpilogueOp.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotEpilogueOp.java	Thu Nov 30 10:40:48 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -37,10 +37,18 @@
 abstract class AArch64HotSpotEpilogueOp extends AArch64BlockEndOp {
 
     private final GraalHotSpotVMConfig config;
+    private final Register thread;
+
+    protected AArch64HotSpotEpilogueOp(LIRInstructionClass<? extends AArch64HotSpotEpilogueOp> c, GraalHotSpotVMConfig config, Register thread) {
+        super(c);
+        this.config = config;
+        this.thread = thread;
+    }
 
     protected AArch64HotSpotEpilogueOp(LIRInstructionClass<? extends AArch64HotSpotEpilogueOp> c, GraalHotSpotVMConfig config) {
         super(c);
         this.config = config;
+        this.thread = null; // no safepoint
     }
 
     protected void leaveFrame(CompilationResultBuilder crb, AArch64MacroAssembler masm, boolean emitSafepoint) {
@@ -49,7 +57,7 @@
         if (emitSafepoint) {
             try (ScratchRegister sc = masm.getScratchRegister()) {
                 Register scratch = sc.getRegister();
-                AArch64HotSpotSafepointOp.emitCode(crb, masm, config, true, scratch, null);
+                AArch64HotSpotSafepointOp.emitCode(crb, masm, config, true, thread, scratch, null);
             }
         }
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java	Thu Nov 30 10:40:48 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -342,7 +342,8 @@
             operand = resultOperandFor(kind, input.getValueKind());
             emitMove(operand, input);
         }
-        append(new AArch64HotSpotReturnOp(operand, getStub() != null, config));
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        append(new AArch64HotSpotReturnOp(operand, getStub() != null, config, thread));
     }
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotNodeLIRBuilder.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotNodeLIRBuilder.java	Thu Nov 30 10:40:48 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -118,8 +118,9 @@
     @Override
     public void visitSafepointNode(SafepointNode i) {
         LIRFrameState info = state(i);
+        Register thread = getGen().getProviders().getRegisters().getThreadRegister();
         Variable scratch = gen.newVariable(LIRKind.value(getGen().target().arch.getWordKind()));
-        append(new AArch64HotSpotSafepointOp(info, getGen().config, scratch));
+        append(new AArch64HotSpotSafepointOp(info, getGen().config, thread, scratch));
     }
 
     @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotReturnOp.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotReturnOp.java	Thu Nov 30 10:40:48 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -33,6 +33,7 @@
 import org.graalvm.compiler.lir.Opcode;
 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
 
+import jdk.vm.ci.code.Register;
 import jdk.vm.ci.meta.Value;
 
 /**
@@ -46,8 +47,8 @@
     @Use({REG, ILLEGAL}) private Value result;
     private final boolean isStub;
 
-    public AArch64HotSpotReturnOp(Value result, boolean isStub, GraalHotSpotVMConfig config) {
-        super(TYPE, config);
+    public AArch64HotSpotReturnOp(Value result, boolean isStub, GraalHotSpotVMConfig config, Register thread) {
+        super(TYPE, config, thread);
         assert validReturnValue(result);
         this.result = result;
         this.isStub = isStub;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSafepointOp.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotSafepointOp.java	Thu Nov 30 10:40:48 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -50,18 +50,20 @@
     @Temp protected AllocatableValue scratchValue;
 
     private final GraalHotSpotVMConfig config;
+    private final Register thread;
 
-    public AArch64HotSpotSafepointOp(LIRFrameState state, GraalHotSpotVMConfig config, AllocatableValue scratch) {
+    public AArch64HotSpotSafepointOp(LIRFrameState state, GraalHotSpotVMConfig config, Register thread, AllocatableValue scratch) {
         super(TYPE);
         this.state = state;
         this.config = config;
+        this.thread = thread;
         this.scratchValue = scratch;
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
         Register scratch = asRegister(scratchValue);
-        emitCode(crb, masm, config, false, scratch, state);
+        emitCode(crb, masm, config, false, thread, scratch, state);
     }
 
     /**
@@ -76,7 +78,15 @@
         return !NumUtil.isSignedNbit(21, pollingPageAddress - config.codeCacheLowBound) || !NumUtil.isSignedNbit(21, pollingPageAddress - config.codeCacheHighBound);
     }
 
-    public static void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm, GraalHotSpotVMConfig config, boolean onReturn, Register scratch, LIRFrameState state) {
+    public static void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm, GraalHotSpotVMConfig config, boolean onReturn, Register thread, Register scratch, LIRFrameState state) {
+        if (config.threadLocalHandshakes) {
+            emitThreadLocalPoll(crb, masm, config, onReturn, thread, scratch, state);
+        } else {
+            emitGlobalPoll(crb, masm, config, onReturn, scratch, state);
+        }
+    }
+
+    private static void emitGlobalPoll(CompilationResultBuilder crb, AArch64MacroAssembler masm, GraalHotSpotVMConfig config, boolean onReturn, Register scratch, LIRFrameState state) {
         if (isPollingPageFar(config)) {
             crb.recordMark(onReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR);
             masm.movNativeAddress(scratch, config.safepointPollingAddress);
@@ -94,4 +104,15 @@
         }
     }
 
+    private static void emitThreadLocalPoll(CompilationResultBuilder crb, AArch64MacroAssembler masm, GraalHotSpotVMConfig config, boolean onReturn, Register thread, Register scratch,
+                    LIRFrameState state) {
+        assert config.threadPollingPageOffset >= 0;
+        masm.ldr(64, scratch, masm.makeAddress(thread, config.threadPollingPageOffset, 8));
+        crb.recordMark(onReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR);
+        if (state != null) {
+            crb.recordInfopoint(masm.position(), state, InfopointReason.SAFEPOINT);
+        }
+        masm.ldr(32, zr, AArch64Address.createBaseRegisterOnlyAddress(scratch));
+    }
+
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Thu Nov 30 10:40:48 2017 -0800
@@ -264,7 +264,8 @@
         if (pollOnReturnScratchRegister == null) {
             pollOnReturnScratchRegister = findPollOnReturnScratchRegister();
         }
-        append(new AMD64HotSpotReturnOp(operand, getStub() != null, pollOnReturnScratchRegister, config));
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        append(new AMD64HotSpotReturnOp(operand, getStub() != null, thread, pollOnReturnScratchRegister, config));
     }
 
     @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Thu Nov 30 10:40:48 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -121,7 +121,8 @@
     @Override
     public void visitSafepointNode(SafepointNode i) {
         LIRFrameState info = state(i);
-        append(new AMD64HotSpotSafepointOp(info, getGen().config, this));
+        Register thread = getGen().getProviders().getRegisters().getThreadRegister();
+        append(new AMD64HotSpotSafepointOp(info, getGen().config, this, thread));
     }
 
     @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotReturnOp.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotReturnOp.java	Thu Nov 30 10:40:48 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -45,13 +45,15 @@
     public static final LIRInstructionClass<AMD64HotSpotReturnOp> TYPE = LIRInstructionClass.create(AMD64HotSpotReturnOp.class);
     @Use({REG, ILLEGAL}) protected Value value;
     private final boolean isStub;
+    private final Register thread;
     private final Register scratchForSafepointOnReturn;
     private final GraalHotSpotVMConfig config;
 
-    AMD64HotSpotReturnOp(Value value, boolean isStub, Register scratchForSafepointOnReturn, GraalHotSpotVMConfig config) {
+    AMD64HotSpotReturnOp(Value value, boolean isStub, Register thread, Register scratchForSafepointOnReturn, GraalHotSpotVMConfig config) {
         super(TYPE);
         this.value = value;
         this.isStub = isStub;
+        this.thread = thread;
         this.scratchForSafepointOnReturn = scratchForSafepointOnReturn;
         this.config = config;
     }
@@ -61,7 +63,7 @@
         leaveFrameAndRestoreRbp(crb, masm);
         if (!isStub) {
             // Every non-stub compile method must have a poll before the return.
-            AMD64HotSpotSafepointOp.emitCode(crb, masm, config, true, null, scratchForSafepointOnReturn);
+            AMD64HotSpotSafepointOp.emitCode(crb, masm, config, true, null, thread, scratchForSafepointOnReturn);
 
             /*
              * We potentially return to the interpreter, and that's an AVX-SSE transition. The only
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotSafepointOp.java	Thu Nov 30 10:40:48 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -58,12 +58,14 @@
     @Temp({OperandFlag.REG, OperandFlag.ILLEGAL}) private AllocatableValue temp;
 
     private final GraalHotSpotVMConfig config;
+    private final Register thread;
 
-    public AMD64HotSpotSafepointOp(LIRFrameState state, GraalHotSpotVMConfig config, NodeLIRBuilderTool tool) {
+    public AMD64HotSpotSafepointOp(LIRFrameState state, GraalHotSpotVMConfig config, NodeLIRBuilderTool tool, Register thread) {
         super(TYPE);
         this.state = state;
         this.config = config;
-        if (isPollingPageFar(config) || ImmutableCode.getValue(tool.getOptions())) {
+        this.thread = thread;
+        if (config.threadLocalHandshakes || isPollingPageFar(config) || ImmutableCode.getValue(tool.getOptions())) {
             temp = tool.getLIRGeneratorTool().newVariable(LIRKind.value(tool.getLIRGeneratorTool().target().arch.getWordKind()));
         } else {
             // Don't waste a register if it's unneeded
@@ -73,7 +75,15 @@
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) {
-        emitCode(crb, asm, config, false, state, temp instanceof RegisterValue ? ((RegisterValue) temp).getRegister() : null);
+        emitCode(crb, asm, config, false, state, thread, temp instanceof RegisterValue ? ((RegisterValue) temp).getRegister() : null);
+    }
+
+    public static void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register thread, Register scratch) {
+        if (config.threadLocalHandshakes) {
+            emitThreadLocalPoll(crb, asm, config, atReturn, state, thread, scratch);
+        } else {
+            emitGlobalPoll(crb, asm, config, atReturn, state, scratch);
+        }
     }
 
     /**
@@ -85,7 +95,7 @@
         return config.forceUnreachable || !isInt(pollingPageAddress - config.codeCacheLowBound) || !isInt(pollingPageAddress - config.codeCacheHighBound);
     }
 
-    public static void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register scratch) {
+    private static void emitGlobalPoll(CompilationResultBuilder crb, AMD64MacroAssembler asm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register scratch) {
         assert !atReturn || state == null : "state is unneeded at return";
         if (ImmutableCode.getValue(crb.getOptions())) {
             JavaKind hostWordKind = JavaKind.Long;
@@ -123,4 +133,18 @@
             asm.testl(rax, new AMD64Address(rip, 0));
         }
     }
+
+    private static void emitThreadLocalPoll(CompilationResultBuilder crb, AMD64MacroAssembler asm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register thread,
+                    Register scratch) {
+        assert !atReturn || state == null : "state is unneeded at return";
+
+        assert config.threadPollingPageOffset >= 0;
+        asm.movptr(scratch, new AMD64Address(thread, config.threadPollingPageOffset));
+        crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR);
+        final int pos = asm.position();
+        if (state != null) {
+            crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
+        }
+        asm.testl(rax, new AMD64Address(scratch));
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Thu Nov 30 10:40:48 2017 -0800
@@ -190,7 +190,8 @@
             operand = resultOperandFor(javaKind, input.getValueKind());
             emitMove(operand, input);
         }
-        append(new SPARCHotSpotReturnOp(operand, getStub() != null, config, getSafepointAddressValue()));
+        Register thread = getProviders().getRegisters().getThreadRegister();
+        append(new SPARCHotSpotReturnOp(operand, getStub() != null, config, thread, getSafepointAddressValue()));
     }
 
     @Override
@@ -383,7 +384,7 @@
 
     public AllocatableValue getSafepointAddressValue() {
         if (this.safepointAddressValue == null) {
-            this.safepointAddressValue = newVariable(LIRKind.value(target().arch.getWordKind()));
+            this.safepointAddressValue = SPARCHotSpotSafepointOp.getSafepointAddressValue(this);
         }
         return this.safepointAddressValue;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java	Thu Nov 30 10:40:48 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -84,7 +84,8 @@
     @Override
     public void visitSafepointNode(SafepointNode i) {
         LIRFrameState info = state(i);
-        append(new SPARCHotSpotSafepointOp(info, getGen().config, gen));
+        Register thread = getGen().getProviders().getRegisters().getThreadRegister();
+        append(new SPARCHotSpotSafepointOp(info, getGen().config, thread, gen));
     }
 
     @Override
@@ -141,9 +142,7 @@
     @Override
     protected void emitPrologue(StructuredGraph graph) {
         super.emitPrologue(graph);
-        AllocatableValue var = getGen().getSafepointAddressValue();
-        append(new SPARCHotSpotSafepointOp.SPARCLoadSafepointPollAddress(var, getGen().config));
-        getGen().append(((HotSpotDebugInfoBuilder) getDebugInfoBuilder()).lockStack());
+        SPARCHotSpotSafepointOp.emitPrologue(this, getGen());
     }
 
     @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotReturnOp.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotReturnOp.java	Thu Nov 30 10:40:48 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -24,7 +24,6 @@
 
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
-import static jdk.vm.ci.code.ValueUtil.asRegister;
 
 import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
@@ -33,6 +32,7 @@
 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
 import org.graalvm.compiler.lir.sparc.SPARCControlFlow.ReturnOp;
 
+import jdk.vm.ci.code.Register;
 import jdk.vm.ci.meta.Value;
 
 /**
@@ -44,15 +44,17 @@
     public static final SizeEstimate SIZE = SizeEstimate.create(2);
 
     @Use({REG, ILLEGAL}) protected Value value;
-    @Use({REG}) protected Value safepointPollAddress;
+    @Use({REG, ILLEGAL}) protected Value safepointPollAddress;
     private final boolean isStub;
     private final GraalHotSpotVMConfig config;
+    private final Register thread;
 
-    SPARCHotSpotReturnOp(Value value, boolean isStub, GraalHotSpotVMConfig config, Value safepointPoll) {
+    SPARCHotSpotReturnOp(Value value, boolean isStub, GraalHotSpotVMConfig config, Register thread, Value safepointPoll) {
         super(TYPE, SIZE);
         this.value = value;
         this.isStub = isStub;
         this.config = config;
+        this.thread = thread;
         this.safepointPollAddress = safepointPoll;
     }
 
@@ -60,7 +62,7 @@
     public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
         if (!isStub) {
             // Every non-stub compile method must have a poll before the return.
-            SPARCHotSpotSafepointOp.emitCode(crb, masm, config, true, null, asRegister(safepointPollAddress));
+            SPARCHotSpotSafepointOp.emitCode(crb, masm, config, true, null, thread, safepointPollAddress);
         }
         ReturnOp.emitCodeHelper(crb, masm);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotSafepointOp.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotSafepointOp.java	Thu Nov 30 10:40:48 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -27,7 +27,10 @@
 
 import org.graalvm.compiler.asm.sparc.SPARCAddress;
 import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
+import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder;
 import org.graalvm.compiler.lir.LIRFrameState;
 import org.graalvm.compiler.lir.LIRInstructionClass;
 import org.graalvm.compiler.lir.Opcode;
@@ -39,6 +42,7 @@
 import jdk.vm.ci.code.ValueUtil;
 import jdk.vm.ci.code.site.InfopointReason;
 import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Value;
 
 /**
  * Emits a safepoint poll.
@@ -49,23 +53,37 @@
     public static final SizeEstimate SIZE = SizeEstimate.create(9);
 
     @State protected LIRFrameState state;
-    @Use({OperandFlag.REG}) AllocatableValue safepointPollAddress;
+    @Use({OperandFlag.REG, OperandFlag.ILLEGAL}) AllocatableValue safepointPollAddress;
     private final GraalHotSpotVMConfig config;
+    private final Register thread;
 
-    public SPARCHotSpotSafepointOp(LIRFrameState state, GraalHotSpotVMConfig config, LIRGeneratorTool tool) {
+    public SPARCHotSpotSafepointOp(LIRFrameState state, GraalHotSpotVMConfig config, Register thread, LIRGeneratorTool tool) {
         super(TYPE, SIZE);
         this.state = state;
         this.config = config;
+        this.thread = thread;
         SPARCHotSpotLIRGenerator lirGen = (SPARCHotSpotLIRGenerator) tool;
         safepointPollAddress = lirGen.getSafepointAddressValue();
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-        emitCode(crb, masm, config, false, state, asRegister(safepointPollAddress));
+        emitCode(crb, masm, config, false, state, thread, safepointPollAddress);
     }
 
-    public static void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register safepointPollAddress) {
+    public static void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register thread,
+                    Value safepointPollAddress) {
+        if (config.threadLocalHandshakes) {
+            emitThreadLocalPoll(crb, masm, config, atReturn, state, thread);
+        } else {
+            emitGlobalPoll(crb, masm, config, atReturn, state, asRegister(safepointPollAddress));
+        }
+    }
+
+    /**
+     * Emit a global safepoint poll.
+     */
+    private static void emitGlobalPoll(CompilationResultBuilder crb, SPARCMacroAssembler masm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register safepointPollAddress) {
         crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR);
         if (state != null) {
             final int pos = masm.position();
@@ -74,6 +92,44 @@
         masm.ldx(new SPARCAddress(safepointPollAddress, 0), g0);
     }
 
+    /**
+     * Emit a thread-local safepoint poll.
+     */
+    private static void emitThreadLocalPoll(CompilationResultBuilder crb, SPARCMacroAssembler masm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register thread) {
+        assert !atReturn || state == null : "state is unneeded at return";
+
+        assert config.threadPollingPageOffset >= 0;
+
+        try (ScratchRegister scratchReg = masm.getScratchRegister()) {
+            Register scratch = scratchReg.getRegister();
+
+            masm.ldx(new SPARCAddress(thread, config.threadPollingPageOffset), scratch);
+
+            crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR);
+            if (state != null) {
+                final int pos = masm.position();
+                crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
+            }
+            masm.ldx(new SPARCAddress(scratch, 0), g0);
+        }
+    }
+
+    static AllocatableValue getSafepointAddressValue(SPARCHotSpotLIRGenerator gen) {
+        if (gen.config.threadLocalHandshakes) {
+            return Value.ILLEGAL;
+        } else {
+            return gen.newVariable(LIRKind.value(gen.target().arch.getWordKind()));
+        }
+    }
+
+    static void emitPrologue(SPARCHotSpotNodeLIRBuilder lir, SPARCHotSpotLIRGenerator gen) {
+        if (!gen.config.threadLocalHandshakes) {
+            AllocatableValue var = gen.getSafepointAddressValue();
+            lir.append(new SPARCHotSpotSafepointOp.SPARCLoadSafepointPollAddress(var, gen.config));
+            gen.append(((HotSpotDebugInfoBuilder) lir.getDebugInfoBuilder()).lockStack());
+        }
+    }
+
     public static class SPARCLoadSafepointPollAddress extends SPARCLIRInstruction {
         public static final LIRInstructionClass<SPARCLoadSafepointPollAddress> TYPE = LIRInstructionClass.create(SPARCLoadSafepointPollAddress.class);
         public static final SizeEstimate SIZE = SizeEstimate.create(2);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java	Thu Nov 30 10:40:48 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -165,6 +165,7 @@
     public final boolean usePopCountInstruction = getFlag("UsePopCountInstruction", Boolean.class);
     public final boolean useAESIntrinsics = getFlag("UseAESIntrinsics", Boolean.class);
     public final boolean useCRC32Intrinsics = getFlag("UseCRC32Intrinsics", Boolean.class);
+    public final boolean threadLocalHandshakes = getFlag("ThreadLocalHandshakes", Boolean.class, false);
 
     private final boolean useMultiplyToLenIntrinsic = getFlag("UseMultiplyToLenIntrinsic", Boolean.class);
     private final boolean useSHA1Intrinsics = getFlag("UseSHA1Intrinsics", Boolean.class);
@@ -594,6 +595,7 @@
     public final int basicLockSize = getFieldValue("CompilerToVM::Data::sizeof_BasicLock", Integer.class, "int");
     public final int basicLockDisplacedHeaderOffset = getFieldOffset("BasicLock::_displaced_header", Integer.class, "markOop");
 
+    public final int threadPollingPageOffset = getFieldOffset("Thread::_polling_page", Integer.class, "address", -1);
     public final int threadAllocatedBytesOffset = getFieldOffset("Thread::_allocated_bytes", Integer.class, "jlong");
 
     public final int tlabRefillWasteIncrement = getFlag("TLABWasteIncrement", Integer.class);
--- a/test/hotspot/jtreg/runtime/handshake/HandshakeTransitionTest.java	Thu Nov 30 14:25:33 2017 -0800
+++ b/test/hotspot/jtreg/runtime/handshake/HandshakeTransitionTest.java	Thu Nov 30 10:40:48 2017 -0800
@@ -29,13 +29,17 @@
 import jdk.test.lib.process.ProcessTools;
 import jdk.test.lib.process.OutputAnalyzer;
 
+import sun.hotspot.WhiteBox;
+
 /*
  * @test HandshakeTransitionTest
  * @summary This does a sanity test of the poll in the native wrapper.
  * @requires vm.debug
  * @library /testlibrary /test/lib
  * @build HandshakeTransitionTest
- * @run main/native HandshakeTransitionTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *                              sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm/native -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI HandshakeTransitionTest
  */
 
 public class HandshakeTransitionTest {
@@ -44,6 +48,7 @@
 
     public static void main(String[] args) throws Exception {
         String lib = System.getProperty("test.nativepath");
+        WhiteBox wb = WhiteBox.getWhiteBox();
         ProcessBuilder pb =
             ProcessTools.createJavaProcessBuilder(
                     true,
@@ -54,6 +59,8 @@
                     "-XX:ParallelGCThreads=1",
                     "-XX:ConcGCThreads=1",
                     "-XX:CICompilerCount=2",
+                    "-XX:+UnlockExperimentalVMOptions",
+                    (wb.getBooleanVMFlag("UseJVMCICompiler") ?  "-XX:+UseJVMCICompiler" : "-XX:-UseJVMCICompiler"),
                     "HandshakeTransitionTest$Test");