RFR: 8165755: [JVMCI] replace use of vm_abort with vm_exit

David Holmes david.holmes at oracle.com
Wed Sep 14 09:25:23 UTC 2016


On 14/09/2016 5:53 PM, Doug Simon wrote:
>
>> On 14 Sep 2016, at 03:42, David Holmes <david.holmes at oracle.com> wrote:
>>
>> Hi Doug,
>>
>> On 14/09/2016 12:41 AM, Doug Simon wrote:
>>> Hi David,
>>>
>>> Do you still have concerns with the webrev in its current form?
>>
>> Sorry, yesterday was "one of those days". :)
>
> No problem, we have those around here sometimes as well ;-)
>
>> tl;dr: Your actual final exit code matches what JVM_Halt does, so that is fine.
>>
>> Your overall initialization and termination approach raises several general concerns. From a usability perspective the idea that JVMCI can terminate the VM at some arbitrary point after application startup is quite alarming!
>
> It’s not completely arbitrary. Top tier compilation kicks in very soon after VM startup for all but HelloWorld type applications. Also, termination happens only due to incorrect  command line in which case I’d say termination is what’s normal/expected.

Yes but people also expect bad command line options to be detected 
before anything else happens that is part of the application logic.

>
>>
>> Looking at the initialization code I'm unclear why it isn't being serialized in some way at a level higher than the SystemDictionary - if it was then you wouldn't need the termination logic to deal with racing threads.
>
> I’m not sure I follow. JVMCI initialization is serialized on the initialization of the jdk.vm.ci.runtime.JVMCI class. Since class initialization errors are preserved, multiple compiler threads can see the same error so will each try to go down the termination path. It’s the latter race that needs serialization which is done now in JVMCICompiler::abort_on_pending_exception.

The code I looked at has the initialization logic called from 
JVMCICompiler::compile_method. I can't say that isn't called from init 
of the JVMCI class, but it sure doesn't sound like it. :)

If the thread that encounters the initial error is holding an 
initialization "lock" (Java monitor in JVMCI's case I expect) when it 
takes the termination path then there's no race in taking that path.

Anyway, just musing.

Cheers,
David

> -Doug
>
>>
>> Cheers,
>> David
>>
>>> -Doug
>>>
>>>> On 12 Sep 2016, at 11:26, Doug Simon <doug.simon at oracle.com> wrote:
>>>>
>>>> Hi David,
>>>>> On 12 Sep 2016, at 03:24, David Holmes <david.holmes at oracle.com> wrote:
>>>>>
>>>>> On 10/09/2016 6:29 AM, Coleen Phillimore wrote:
>>>>>> On 9/9/16 3:31 PM, Doug Simon wrote:
>>>>>>> Is vm_exit_during_initialization still the right choice when this
>>>>>>> could be after VM initialization? JVMCI initialization is lazy and can
>>>>>>> happen after the application has started.
>>>>>>
>>>>>> I don't actually know then.  vm_exit tries to get threads to a safepoint
>>>>>> first, but vm_abort(false) just shuts down the jvm. There aren't a lot
>>>>>> of places we terminate the jvm.  Maybe David Holmes knows.
>>>>>
>>>>> If JVMCI initialization is lazy and can happen after the application is started, why should it be a fatal error to fail to initialize it? How is the initialization triggered? Is there a synchronous call that could throw an exception? How does the user know that initialization failure will result in termination?
>>>>
>>>> JVMCI initialization is triggered by the first top tier compilation (when UseJVMCICompiler is true) or by an explicit request via the Java API to the JVMCI system. In the latter case, an exception is propagated to the caller who can decide what to do with it. However, in the former case, initialization is triggered by the CompileBroker on a compilation thread. We could make a failure during JVMCI initialization disable compilation but I’m sure that would be more confusing to a user than a VM exit clearly stating the invalid configuration option given. There’s already lazy configuration checking in other compilers that can cause the VM to exit (e.g. Compile::pd_compiler2_init in c2_init_x86.cpp) so this is not too different.
>>>>
>>>>> Can you not at least eagerly validate command-line options during VM initialization, even if you don't actually initialize JVMCI fully?
>>>>
>>>> Unfortunately not. The command line options are discovered (via a service loader) during initialization and this kind of activity is what we want to avoid during early VM startup.
>>>>
>>>>>
>>>>> That aside it sounds like you want JVMCI initialization to do the equivalent of either Runtime.exit or Runtime.halt, depending on the exact termination semantics you want. If you call vm_exit directly then you get something like Runtime.halt
>>>>
>>>> Yes, we want Runtime.halt semantics in the case where invalid JVMCI options are specified.
>>>>
>>>> -Doug
>>>>
>>>>> David
>>>>> -----
>>>>>
>>>>>> Coleen
>>>>>>
>>>>>>>
>>>>>>> Sent from my iPhone
>>>>>>>
>>>>>>>> On Sep 9, 2016, at 9:23 PM, Coleen Phillimore
>>>>>>>> <coleen.phillimore at oracle.com> wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> I think you want vm_exit_during_initialization() for that. Definitely
>>>>>>>> not vm_abort, cause then it looks like an internal error/crash.
>>>>>>>>
>>>>>>>> Coleen
>>>>>>>>
>>>>>>>>> On 9/9/16 2:33 PM, Doug Simon wrote:
>>>>>>>>> Can someone from the runtime team confirm that using vm_exit
>>>>>>>>> (instead of vm_abort) is the best way to stop the VM when JVMCI
>>>>>>>>> initialization fails (e.g., when invalid JVMCI options are provided
>>>>>>>>> on the command line). Thanks!
>>>>>>>>>
>>>>>>>>> -Doug
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>> On 09 Sep 2016, at 19:48, Christian Thalinger
>>>>>>>>>> <cthalinger at twitter.com> wrote:
>>>>>>>>>>
>>>>>>>>>> I think this looks fine but maybe we should ask the runtime folks.
>>>>>>>>>>
>>>>>>>>>>> On Sep 8, 2016, at 11:01 PM, Doug Simon <doug.simon at oracle.com>
>>>>>>>>>>> wrote:
>>>>>>>>>>>
>>>>>>>>>>> Calling vm_abort from multiple threads can cause nasty crashes
>>>>>>>>>>> such as double free errors. We've seen this in Graal during JVMCI
>>>>>>>>>>> initialization when an unknown Graal option is encountered.
>>>>>>>>>>> Multiple compiler threads try to initialize JVMCI which fails with
>>>>>>>>>>> an exception indicating the bad option:
>>>>>>>>>>>
>>>>>>>>>>> Uncaught exception at
>>>>>>>>>>> /scratch/graaluser/buildslave/buildlog/ci_executor/main/graal-jvmci-8/src/share/vm/jvmci/jvmciCompiler.cpp:127
>>>>>>>>>>>
>>>>>>>>>>> java.lang.ExceptionInInitializerError
>>>>>>>>>>>     at
>>>>>>>>>>> jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime(HotSpotJVMCIRuntime.java:85)
>>>>>>>>>>>
>>>>>>>>>>>     at jdk.vm.ci.runtime.JVMCI.initializeRuntime(Native Method)
>>>>>>>>>>>     at jdk.vm.ci.runtime.JVMCI.<clinit>(JVMCI.java:58)
>>>>>>>>>>> Caused by: java.lang.IllegalArgumentException: Could not find
>>>>>>>>>>> option OptSomethingThatDoesNotExcist
>>>>>>>>>>>     at
>>>>>>>>>>> com.oracle.graal.options.OptionsParser.parseOption(OptionsParser.java:134)
>>>>>>>>>>>
>>>>>>>>>>>     at
>>>>>>>>>>> com.oracle.graal.options.OptionsParser.parseOptions(OptionsParser.java:62)
>>>>>>>>>>>
>>>>>>>>>>>     at
>>>>>>>>>>> com.oracle.graal.hotspot.HotSpotGraalCompilerFactory.initializeOptions(HotSpotGraalCompilerFactory.java:156)
>>>>>>>>>>>
>>>>>>>>>>>     at
>>>>>>>>>>> com.oracle.graal.hotspot.HotSpotGraalCompilerFactory.onSelection(HotSpotGraalCompilerFactory.java:86)
>>>>>>>>>>>
>>>>>>>>>>>     at
>>>>>>>>>>> jdk.vm.ci.hotspot.HotSpotJVMCICompilerConfig.getCompilerFactory(HotSpotJVMCICompilerConfig.java:96)
>>>>>>>>>>>
>>>>>>>>>>>     at
>>>>>>>>>>> jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.<init>(HotSpotJVMCIRuntime.java:277)
>>>>>>>>>>>
>>>>>>>>>>>     at
>>>>>>>>>>> jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.<init>(HotSpotJVMCIRuntime.java:67)
>>>>>>>>>>>
>>>>>>>>>>>     at
>>>>>>>>>>> jdk.vm.ci.hotspot.HotSpotJVMCIRuntime$DelayedInit.<clinit>(HotSpotJVMCIRuntime.java:75)
>>>>>>>>>>>
>>>>>>>>>>>     at
>>>>>>>>>>> jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime(HotSpotJVMCIRuntime.java:85)
>>>>>>>>>>>
>>>>>>>>>>>     at jdk.vm.ci.runtime.JVMCI.initializeRuntime(Native Method)
>>>>>>>>>>>     at jdk.vm.ci.runtime.JVMCI.<clinit>(JVMCI.java:58)
>>>>>>>>>>>
>>>>>>>>>>> The native JVMCI code then tries to exit the VM by calling
>>>>>>>>>>> vm_abort. If multiple compiler threads do this concurrently,
>>>>>>>>>>> certain destructors can be called twice as shown by these thread
>>>>>>>>>>> dumps:
>>>>>>>>>>>
>>>>>>>>>>> thread #26: tid = 0x0019, 0x00007fff84280124
>>>>>>>>>>> libsystem_malloc.dylib`szone_size + 227, stop reason = signal SIGSTOP
>>>>>>>>>>> frame #0: 0x00007fff84280124 libsystem_malloc.dylib`szone_size + 227
>>>>>>>>>>> frame #1: 0x00007fff8427fed5 libsystem_malloc.dylib`free + 61
>>>>>>>>>>> frame #2: 0x000000010ac95963
>>>>>>>>>>> libjvm.dylib`os::free(memblock=0x00007fedc86226e0,
>>>>>>>>>>> memflags=mtInternal) + 307 at os.cpp:711
>>>>>>>>>>> frame #3: 0x000000010a2afc54
>>>>>>>>>>> libjvm.dylib`FreeHeap(p=0x00007fedc86226e0, memflags=mtInternal) +
>>>>>>>>>>> 52 at allocation.inline.hpp:93
>>>>>>>>>>> frame #4: 0x000000010acf0a9f
>>>>>>>>>>> libjvm.dylib`PerfData::~PerfData(this=0x00007fedc8622650) + 63 at
>>>>>>>>>>> perfData.cpp:116
>>>>>>>>>>> frame #5: 0x000000010acf0ae5
>>>>>>>>>>> libjvm.dylib`PerfData::~PerfData(this=0x00007fedc8622650) + 21 at
>>>>>>>>>>> perfData.cpp:114
>>>>>>>>>>> frame #6: 0x000000010acf163d
>>>>>>>>>>> libjvm.dylib`PerfDataManager::destroy() + 109 at perfData.cpp:287
>>>>>>>>>>> frame #7: 0x000000010acf3f4d libjvm.dylib`perfMemory_exit() + 61
>>>>>>>>>>> at perfMemory.cpp:74
>>>>>>>>>>> frame #8: 0x000000010ac9bb0d libjvm.dylib`os::shutdown() + 13 at
>>>>>>>>>>> os_bsd.cpp:1130
>>>>>>>>>>> frame #9: 0x000000010ac9bb55
>>>>>>>>>>> libjvm.dylib`os::abort(dump_core=false) + 21 at os_bsd.cpp:1150
>>>>>>>>>>> frame #10: 0x000000010a9188e7
>>>>>>>>>>> libjvm.dylib`vm_abort(dump_core=false) + 39 at java.cpp:666
>>>>>>>>>>> frame #11: 0x000000010aa4f1e7
>>>>>>>>>>> libjvm.dylib`JVMCIRuntime::abort_on_pending_exception(exception=Handle
>>>>>>>>>>> @ 0x000070000175b208, message="Uncaught exception at
>>>>>>>>>>> /Users/dsimon/graal/graal-jvmci-8/src/share/vm/jvmci/jvmciCompiler.cpp:127",
>>>>>>>>>>> dump_core=false) + 167 at jvmciRuntime.cpp:992
>>>>>>>>>>> frame #12: 0x000000010aa17017
>>>>>>>>>>> libjvm.dylib`JVMCICompiler::compile_method(this=0x00007fedcb203050, method=0x000070000175b8d8,
>>>>>>>>>>> entry_bci=-1, env=0x000070000175b8f0) + 311 at jvmciCompiler.cpp:127
>>>>>>>>>>> frame #13: 0x000000010a656cd2
>>>>>>>>>>> libjvm.dylib`CompileBroker::invoke_compiler_on_method(task=0x00007fedc853ca30)
>>>>>>>>>>> + 1314 at compileBroker.cpp:2207
>>>>>>>>>>>
>>>>>>>>>>> thread #23: tid = 0x0016, 0x00007fff91fcb122
>>>>>>>>>>> libsystem_kernel.dylib`__semwait_signal_nocancel + 10, stop reason
>>>>>>>>>>> = signal SIGSTOP
>>>>>>>>>>> frame #0: 0x00007fff91fcb122
>>>>>>>>>>> libsystem_kernel.dylib`__semwait_signal_nocancel + 10
>>>>>>>>>>> frame #1: 0x00007fff9578c318 libsystem_c.dylib`nanosleep$NOCANCEL
>>>>>>>>>>> + 188
>>>>>>>>>>> frame #2: 0x00007fff957b62ce libsystem_c.dylib`usleep$NOCANCEL + 54
>>>>>>>>>>> frame #3: 0x00007fff957e46e9 libsystem_c.dylib`abort + 139
>>>>>>>>>>> frame #4: 0x00007fff8428c396 libsystem_malloc.dylib`szone_error + 626
>>>>>>>>>>> frame #5: 0x000000010ac95963
>>>>>>>>>>> libjvm.dylib`os::free(memblock=0x00007fedc8601cd0,
>>>>>>>>>>> memflags=mtInternal) + 307 at os.cpp:711
>>>>>>>>>>> frame #6: 0x000000010a2afc54
>>>>>>>>>>> libjvm.dylib`FreeHeap(p=0x00007fedc8601cd0, memflags=mtInternal) +
>>>>>>>>>>> 52 at allocation.inline.hpp:93
>>>>>>>>>>> frame #7: 0x000000010acf0a9f
>>>>>>>>>>> libjvm.dylib`PerfData::~PerfData(this=0x00007fedc8601c60) + 63 at
>>>>>>>>>>> perfData.cpp:116
>>>>>>>>>>> frame #8: 0x000000010acf0ae5
>>>>>>>>>>> libjvm.dylib`PerfData::~PerfData(this=0x00007fedc8601c60) + 21 at
>>>>>>>>>>> perfData.cpp:114
>>>>>>>>>>> frame #9: 0x000000010acf163d
>>>>>>>>>>> libjvm.dylib`PerfDataManager::destroy() + 109 at perfData.cpp:287
>>>>>>>>>>> frame #10: 0x000000010acf3f4d libjvm.dylib`perfMemory_exit() + 61
>>>>>>>>>>> at perfMemory.cpp:74
>>>>>>>>>>> frame #11: 0x000000010ac9bb0d libjvm.dylib`os::shutdown() + 13 at
>>>>>>>>>>> os_bsd.cpp:1130
>>>>>>>>>>> frame #12: 0x000000010ac9bb55
>>>>>>>>>>> libjvm.dylib`os::abort(dump_core=false) + 21 at os_bsd.cpp:1150
>>>>>>>>>>> frame #13: 0x000000010a9188e7
>>>>>>>>>>> libjvm.dylib`vm_abort(dump_core=false) + 39 at java.cpp:666
>>>>>>>>>>> frame #14: 0x000000010aa4f1e7
>>>>>>>>>>> libjvm.dylib`JVMCIRuntime::abort_on_pending_exception(exception=Handle
>>>>>>>>>>> @ 0x0000700001452208, message="Uncaught exception at
>>>>>>>>>>> /Users/dsimon/graal/graal-jvmci-8/src/share/vm/jvmci/jvmciCompiler.cpp:127",
>>>>>>>>>>> dump_core=false) + 167 at jvmciRuntime.cpp:992
>>>>>>>>>>> frame #15: 0x000000010aa17017
>>>>>>>>>>> libjvm.dylib`JVMCICompiler::compile_method(this=0x00007fedcb203050, method=0x00007000014528d8,
>>>>>>>>>>> entry_bci=-1, env=0x00007000014528f0) + 311 at jvmciCompiler.cpp:127
>>>>>>>>>>> frame #16: 0x000000010a656cd2
>>>>>>>>>>> libjvm.dylib`CompileBroker::invoke_compiler_on_method(task=0x00007fedc862a320)
>>>>>>>>>>> + 1314 at compileBroker.cpp:2207
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> This webrev replaces calls to vm_abort() with before_exit() +
>>>>>>>>>>> vm_exit(). The latter is thread safe.
>>>>>>>>>>>
>>>>>>>>>>> https://bugs.openjdk.java.net/browse/JDK-8165755
>>>>>>>>>>> http://cr.openjdk.java.net/~dnsimon/8165755/
>>>>>>>>>>>
>>>>>>>>>>> -Doug
>>>>>>
>>>>
>>>
>


More information about the hotspot-dev mailing list