Re: RFR(XS): 8245126 Kitchensink fails with: assert(!method->is_old()) failed: Should not be installing old methods

2020-05-31 Thread serguei.spit...@oracle.com

  
  
On 5/31/20 23:16,
  serguei.spit...@oracle.com wrote:


  Hi Dean,

To check the is_old as you suggest the target method has to be
passed
to the cache_jvmti_state() as argument. Is it what you are
suggesting?
Just want to make sure I understand you correctly.

The cache_jvmti_state() and cache_dtrace_flags() are called in
the
CompileBroker::init_compiler_runtime() for a ciEnv with the NULL
CompileTask
which looks unnecessary (or I don't understand it):

bool CompileBroker::init_compiler_runtime() {
  CompilerThread* thread = CompilerThread::current();
  . . .
    ciEnv ci_env((CompileTask*)NULL);
    // Cache Jvmti state
    ci_env.cache_jvmti_state();
    // Cache DTrace flags
    ci_env.cache_dtrace_flags();

The JVMCI has a separate implementation for ciEnv which is
jvmciEnv and
its own set of cache_jvmti_state() and jvmti_state_changed()
functions.
Both are not called in the JVMCI case.
So, these checks look as broken in JVMCI now.

Not sure, I have enough compiler knowledge to fix this at this
stage of release.
Would it better to file a separate hotspot/compiler RFE targeted
to 16?
It can be assigned to me if it helps.
  


I forgot to tell that this RFE should probably include some
refactoring
to make all this more clear and elegant.

Thanks,
Serguei


   Thanks,
Serguei


On 5/28/20 10:54, Dean Long wrote:
  
  
Sure, you could just have cache_jvmti_state() return a boolean
to bail out immediately for is_old.

dl

On 5/28/20 7:23 AM, serguei.spit...@oracle.com wrote:


  Hi Dean,

Thank you for looking at this!
Okay. Let me check what cab be done in this direction.
There is no point to cache is_old. The compilation has to
bail out if it is discovered to be true.

Thanks,
Serguei


On 5/28/20 00:59, Dean Long wrote:
  
  
This seems OK as long as the memory barriers in the thread
state transitions prevent the C++ compiler from doing
something like reading is_old before reading
redefinition_count.  I would feel better if both JVMCI and
C1/C2 cached is_old and redefinition_count at the same time
(making sure to be in the _thread_in_vm state), then bail
out based on the cached value of is_old.

dl

On 5/26/20 12:04 AM, serguei.spit...@oracle.com
  wrote:


  On 5/25/20 23:39, serguei.spit...@oracle.com
wrote:
  
  
Please, review a fix for:
  https://bugs.openjdk.java.net/browse/JDK-8245126

Webrev:
  http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/kitchensink-comp.1/


Summary:
  The Kitchensink stress test with the Instrumentation
module enabled does
  a lot of class retransformations in parallel with all
other stressing.
  It provokes the assert at the compiled code
installation time:
    assert(!method->is_old()) failed: Should not be
installing old methods

  The problem is that the
CompileBroker::invoke_compiler_on_method in C2 version
  (non-JVMCI tiered compilation) is missing the check
that exists in the JVMCI
  part of implementation:
2148 // Skip redefined methods
2149 if (target_handle->is_old()) {
2150   failure_reason = "redefined method";
2151   retry_message = "not retryable";
2152   compilable = ciEnv::MethodCompilable_never;
2153 } else {
. . .
2168 }

  The fix is to add this check.
  
  
  Sorry, forgot to explain one thing.
  Compiler code has a special mechanism to ensure the JVMTI
  class redefinition did
  not happen while the method was compiled, so all the
  assumptions remain correct.
2190 // Cache Jvmti state
  2191 ci_env.cache_jvmti_state();
  Part of this is a check that the value of
  JvmtiExport::redefinition_count() is
  cached in ciEnv variable: _jvmti_redefinition_count.
  The JvmtiExport::redefinition_count() val

Re: RFR(XS): 8245126 Kitchensink fails with: assert(!method->is_old()) failed: Should not be installing old methods

2020-05-31 Thread serguei.spit...@oracle.com

  
  
Hi Dean,
  
  To check the is_old as you suggest the target method has to be
  passed
  to the cache_jvmti_state() as argument. Is it what you are
  suggesting?
  Just want to make sure I understand you correctly.
  
  The cache_jvmti_state() and cache_dtrace_flags() are called in the
  CompileBroker::init_compiler_runtime() for a ciEnv with the NULL
  CompileTask
  which looks unnecessary (or I don't understand it):
  
  bool CompileBroker::init_compiler_runtime() {
    CompilerThread* thread = CompilerThread::current();
    . . .
      ciEnv ci_env((CompileTask*)NULL);
      // Cache Jvmti state
      ci_env.cache_jvmti_state();
      // Cache DTrace flags
      ci_env.cache_dtrace_flags();
  
  The JVMCI has a separate implementation for ciEnv which is
  jvmciEnv and
  its own set of cache_jvmti_state() and jvmti_state_changed()
  functions.
  Both are not called in the JVMCI case.
  So, these checks look as broken in JVMCI now.
  
  Not sure, I have enough compiler knowledge to fix this at this
  stage of release.
  Would it better to file a separate hotspot/compiler RFE targeted
  to 16?
  It can be assigned to me if it helps.
  
  Thanks,
  Serguei
  
  
  On 5/28/20 10:54, Dean Long wrote:

 Sure,
  you could just have cache_jvmti_state() return a boolean to bail
  out immediately for is_old.
  
  dl
  
  On 5/28/20 7:23 AM, serguei.spit...@oracle.com wrote:
  
  
Hi Dean,
  
  Thank you for looking at this!
  Okay. Let me check what cab be done in this direction.
  There is no point to cache is_old. The compilation has to bail
  out if it is discovered to be true.
  
  Thanks,
  Serguei
  
  
  On 5/28/20 00:59, Dean Long wrote:


  This seems OK as long as the memory barriers in the thread
  state transitions prevent the C++ compiler from doing
  something like reading is_old before reading
  redefinition_count.  I would feel better if both JVMCI and
  C1/C2 cached is_old and redefinition_count at the same time
  (making sure to be in the _thread_in_vm state), then bail out
  based on the cached value of is_old.
  
  dl
  
  On 5/26/20 12:04 AM, serguei.spit...@oracle.com
wrote:
  
  
On 5/25/20 23:39, serguei.spit...@oracle.com
  wrote:


  Please, review a fix for:
    https://bugs.openjdk.java.net/browse/JDK-8245126
  
  Webrev:
    http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/kitchensink-comp.1/
  
  
  Summary:
    The Kitchensink stress test with the Instrumentation
  module enabled does
    a lot of class retransformations in parallel with all
  other stressing.
    It provokes the assert at the compiled code installation
  time:
      assert(!method->is_old()) failed: Should not be
  installing old methods
  
    The problem is that the
  CompileBroker::invoke_compiler_on_method in C2 version
    (non-JVMCI tiered compilation) is missing the check that
  exists in the JVMCI
    part of implementation:
  2148 // Skip redefined methods
2149 if (target_handle->is_old()) {
2150   failure_reason = "redefined method";
2151   retry_message = "not retryable";
2152   compilable = ciEnv::MethodCompilable_never;
2153 } else {
. . .
2168 }

  The fix is to add this check.


Sorry, forgot to explain one thing.
Compiler code has a special mechanism to ensure the JVMTI
class redefinition did
not happen while the method was compiled, so all the
assumptions remain correct.
  2190 // Cache Jvmti state
  2191 ci_env.cache_jvmti_state();
Part of this is a check that the value of
JvmtiExport::redefinition_count() is
cached in ciEnv variable: _jvmti_redefinition_count.
The JvmtiExport::redefinition_count() value change means a
class redefinition
happened which also implies some of methods may become old.
However, the method being compiled can be already old at the
point where the
redefinition counter is cached, so the redefinition counter
check does not help much.

Thanks,
Serguei


  Testing:
  Ran Kitchensink test with the Instrumentation mod

Re: RFR JDK-8232222: Set state to 'linked' when an archived class is restored at runtime

2020-05-31 Thread David Holmes

Hi Jiangli,

On 29/05/2020 9:02 am, Jiangli Zhou wrote:

(Looping in serviceability-dev@openjdk.java.net ...)

Hi David and Ioi,

On Wed, May 27, 2020 at 11:15 PM David Holmes  wrote:


Hi Jiangli,

On 28/05/2020 11:35 am, Ioi Lam wrote:



On 5/27/20 6:17 PM, Jiangli Zhou wrote:

On Wed, May 27, 2020 at 1:56 PM Ioi Lam  wrote:

On 5/26/20 6:21 PM, Jiangli Zhou wrote:


Focusing on the link state for archived classes in this thread, I
updated the webrev to only set archived boot classes to 'linked' state
at restore time. More investigations can be done for archived classes
for other builtin loaders.

https://bugs.openjdk.java.net/browse/JDK-823
http://cr.openjdk.java.net/~jiangli/823/webrev.02/

Please let me know if there is any additional concerns to the change.

Best regards,
Jiangli


Hi Jiangli,

I think the change is fine. I am wondering if this

2530   if (!BytecodeVerificationLocal &&
2531loader_data->is_the_null_class_loader_data()) {
2532 _init_state = linked;
2533   }


can be changed to

  if (!BytecodeVerificationLocal &&
  loader_data->is_the_null_class_loader_data() &&
  !JvmtiExport::should_post_class_prepare())

That way, there's no need to change systemDictionary.cpp.



I was going to take the suggestion, but realized that it would add
unnecessary complications for archived boot classes with class
pre-initialization support. Some agents may set
JvmtiExport::should_post_class_prepare(). It's worthwhile to support
class pre-init uniformly for archived boot classes with
JvmtiExport::should_post_class_prepare() enabled or disabled.


This would introduce behavioral changes when JVMTI is enabled:

+ The order of JvmtiExport::post_class_prepare is different than before
+ JvmtiExport::post_class_prepare may be called for a class that was not
called before (if the class is never linked during run time)
+ JvmtiExport::post_class_prepare was called inside the init_lock, now
it's called outside of the init_lock


I have to say I share Ioi's concerns here. This change will impact JVM
TI agents in a way we can't be sure of. From a specification perspective
I think we are fine as linking can be lazy or eager, so there's no
implied order either. But this would be a behavioural change that will
be observable by agents. (I'm less concerned about the init_lock
situation as it seems potentially buggy to me to call out to an agent
with the init_lock held in the first place! I find it hard to imagine an
agent only working correctly if the init_lock is held.)



Totally agree that we need to be very careful here (that's also part
of the reason why I separated this into an individual RFE for the
dedicated discussion). David, thanks for the analysis from the spec
perspective! Agreed with the init_lock comment also. In the future, I
think we can even get rid of the needs for init_lock completely for
some of the pre-initialized classes.

This change has gone through extensive testing since the later part of
last year and has been in use (with the default CDS) with agents that
do post_class_prepare. Hopefully that would ease some of the concerns.


That is good to know, but that is just one sample of a set of agents.


This would need a CSR request and involvement of the serviceabilty folk,
to work through any potential issues.



I've looped in serviceability-dev@openjdk.java.net for this
discussion. Chris or Serguei could you please take a look of the
change, http://cr.openjdk.java.net/~jiangli/823/webrev.02/,
specifically the JvmtiExport::post_class_prepare change in
systemDictionary.cpp.

Filing a CSR request sounds good to me. The CSR looks after source,
binary, and behavioral compatibility. From a behavior point of view,
the change most likely does not cause any visible effects to a JVMTI
agent (based on what's observed in testing and usages). What should be
included in the CSR?


The CSR request should explain the behavioural change that will be 
observable by agents, and all of the potential compatibility issues that 
might arise from that - pointing out of course that as the spec (JVMS 
5.4**) allows for eager or lazy linking, agents shouldn't be relying on 
the exact timing or order of events.


** I note this section has some additional constraints regarding 
dynamically computed constants that might also come into play with this 
pre-linking for CDS classes.


Cheers,
David
-


Ioi's suggestion avoids this problem, but, as you note, at the expense
of disabling this optimisation if an agent is attached and wants class
prepare events.



Right, if we handle that case conditionally, we would alway need to
store the cached static field values separately since the dump time
cannot foresee if the runtime can set boot classes in 'linked' state
(and 'fully_initialized' state with the planned changes) at restore
time. As a result, we need to handle all pre-initialized static fields
like what we are doing today, which is storing them in the archived
cl

Re: RFR: JDK-8225056 VM support for sealed classes

2020-05-31 Thread David Holmes

Hi Harold,

On 1/06/2020 8:57 am, Harold Seigel wrote:

Thanks for the comments.

Here's version 3 of the JDK and VM changes for sealed classes.

full webrev: 
http://cr.openjdk.java.net/~hseigel/sealedClasses.8225056.3/webrev/


The new webrev contains just the following three changes:

 1. The sealed classes API's in Class.java (permittedSubclasses() and
isSealed()) were revised and, in particular, API
permittedSubclasses() no longer uses reflection.


For those following along we have presently abandoned the attempt to 
cache the array in ReflectionData.


Current changes look okay. But I note from the CSR there appears to be a 
further minor update to the javadoc coming.



 2. An unneeded 'if' statement was removed from
JVM_GetPermittedSubclasses() (pointed out by David.)


Looks good.


 3. VM runtime test files SealedUnnamedModuleIntfTest.java and
Permitted.java were changed to add a test case for a non-public
permitted subclass and its sealed superclass being in the same
module and package.


Looks good.

Additionally, two follow on RFE's will be filed.  One to add additional 
VM sealed classes tests 


Thanks. I think there is a more mechanical approach to testing here that 
will allow the complete matrix to be easily covered with minimal 
duplication between testing for named and unnamed modules.


and one to improve the implementations of the 
sealed classes API's in Class.java.


Thanks.

David
-


Thanks, Harold

On 5/28/2020 8:30 PM, David Holmes wrote:


Hi Harold,

Sorry Mandy's comment raised a couple of issues ...

On 29/05/2020 7:12 am, Mandy Chung wrote:

Hi Harold,

On 5/27/20 1:35 PM, Harold Seigel wrote:


Incremental webrev: 
http://cr.openjdk.java.net/~hseigel/sealedClasses.8225056.incr.2/


full webrev: 
http://cr.openjdk.java.net/~hseigel/sealedClasses.8225056.2/webrev/



Class.java

4406 ReflectionData rd = reflectionData();
4407 ClassDesc[] tmp = rd.permittedSubclasses;
4408 if (tmp != null) {
4409 return tmp;
4410 }
4411
4412 if (isArray() || isPrimitive()) {
4413 rd.permittedSubclasses = new ClassDesc[0];
4414 return rd.permittedSubclasses;
4415 }

This causes an array class or primitive type to create a 
ReflectionData.   It should first check if this is non-sealed class 
and returns a constant empty array.


It can't check if this is a non-sealed class as the isSealed() check 
calls the above code! But for arrays and primitives which can't be 
sealed we should just do:


4412 if (isArray() || isPrimitive()) {
4413 return new ClassDesc[0];
4414 }

But this then made me realize that we need to be creating defensive 
copies of the returned arrays, as happens with other APIs that use 
ReflectionData.


Backing up a bit I complained that:

public boolean isSealed() {
return permittedSubclasses().length != 0;
}

is a very inefficient way to answer the question as to whether a class 
is sealed, so I suggested that the result of permittedSubclasses() be 
cached. Caching is not without its own issues as we are discovering, 
and when you add in defensive copies this seems to be trading one 
inefficiency for another. For nestmates we don't cache 
getNestMembers() because we don;t think it will be called often - it 
is there to complete the introspection API of Class rather than being 
anticipated as used in a regular programmatic sense. I expect the same 
is true for permittedSubclasses(). Do we expect isSealed() to be used 
often or is it too just there for completeness? If just for 
completeness then perhaps a VM query would be a better compromise on 
the efficiency front? Otherwise I can accept the current 
implementation of isSealed(), and a non-caching permittedClasses() for 
this initial implementation of sealed classes. If efficiency turns out 
to be a problem for isSealed() then we can revisit it then.


Thanks,
David


In fact, ReflectionData caches the derived names and reflected 
members for performance and also they may be invalidated when the 
class is redefined.   It might be okay to add 
ReflectionData::permittedSubclasses while `PermittedSubclasses` 
attribute can't be redefined and getting this attribute is not 
performance sensitive.   For example, the result of `getNestMembers` 
is not cached in ReflectionData.  It may be better not to add it in 
ReflectionData for modifiable and performance-sensitive data.



4421 tmp = new ClassDesc[subclassNames.length];
4422 int i = 0;
4423 for (String subclassName : subclassNames) {
4424 try {
4425 tmp[i++] = ClassDesc.of(subclassName.replace('/', '.'));
4426 } catch (IllegalArgumentException iae) {
4427 throw new InternalError("Invalid type in permitted subclasses 
information: " + subclassName, iae);

4428 }
4429 }
Nit: rename tmp to some other name e.g. descs

I read the JVMS but it isn't clear to me that the VM will validate 
the names in `PermittedSubclasses`attribute are valid class 
descriptors.   I see ConstantPool::is_klass_or_reference check but 
can't find where it validates the name is 

Re: RFR: JDK-8225056 VM support for sealed classes

2020-05-31 Thread Harold Seigel

Thanks for the comments.

Here's version 3 of the JDK and VM changes for sealed classes.

full webrev: 
http://cr.openjdk.java.net/~hseigel/sealedClasses.8225056.3/webrev/


The new webrev contains just the following three changes:

1. The sealed classes API's in Class.java (permittedSubclasses() and
   isSealed()) were revised and, in particular, API
   permittedSubclasses() no longer uses reflection.
2. An unneeded 'if' statement was removed from
   JVM_GetPermittedSubclasses() (pointed out by David.)
3. VM runtime test files SealedUnnamedModuleIntfTest.java and
   Permitted.java were changed to add a test case for a non-public
   permitted subclass and its sealed superclass being in the same
   module and package.

Additionally, two follow on RFE's will be filed.  One to add additional 
VM sealed classes tests and one to improve the implementations of the 
sealed classes API's in Class.java.


Thanks, Harold

On 5/28/2020 8:30 PM, David Holmes wrote:


Hi Harold,

Sorry Mandy's comment raised a couple of issues ...

On 29/05/2020 7:12 am, Mandy Chung wrote:

Hi Harold,

On 5/27/20 1:35 PM, Harold Seigel wrote:


Incremental webrev: 
http://cr.openjdk.java.net/~hseigel/sealedClasses.8225056.incr.2/


full webrev: 
http://cr.openjdk.java.net/~hseigel/sealedClasses.8225056.2/webrev/



Class.java

4406 ReflectionData rd = reflectionData();
4407 ClassDesc[] tmp = rd.permittedSubclasses;
4408 if (tmp != null) {
4409 return tmp;
4410 }
4411
4412 if (isArray() || isPrimitive()) {
4413 rd.permittedSubclasses = new ClassDesc[0];
4414 return rd.permittedSubclasses;
4415 }

This causes an array class or primitive type to create a 
ReflectionData.   It should first check if this is non-sealed class 
and returns a constant empty array.


It can't check if this is a non-sealed class as the isSealed() check 
calls the above code! But for arrays and primitives which can't be 
sealed we should just do:


4412 if (isArray() || isPrimitive()) {
4413 return new ClassDesc[0];
4414 }

But this then made me realize that we need to be creating defensive 
copies of the returned arrays, as happens with other APIs that use 
ReflectionData.


Backing up a bit I complained that:

public boolean isSealed() {
return permittedSubclasses().length != 0;
}

is a very inefficient way to answer the question as to whether a class 
is sealed, so I suggested that the result of permittedSubclasses() be 
cached. Caching is not without its own issues as we are discovering, 
and when you add in defensive copies this seems to be trading one 
inefficiency for another. For nestmates we don't cache 
getNestMembers() because we don;t think it will be called often - it 
is there to complete the introspection API of Class rather than being 
anticipated as used in a regular programmatic sense. I expect the same 
is true for permittedSubclasses(). Do we expect isSealed() to be used 
often or is it too just there for completeness? If just for 
completeness then perhaps a VM query would be a better compromise on 
the efficiency front? Otherwise I can accept the current 
implementation of isSealed(), and a non-caching permittedClasses() for 
this initial implementation of sealed classes. If efficiency turns out 
to be a problem for isSealed() then we can revisit it then.


Thanks,
David


In fact, ReflectionData caches the derived names and reflected 
members for performance and also they may be invalidated when the 
class is redefined.   It might be okay to add 
ReflectionData::permittedSubclasses while `PermittedSubclasses` 
attribute can't be redefined and getting this attribute is not 
performance sensitive.   For example, the result of `getNestMembers` 
is not cached in ReflectionData.  It may be better not to add it in 
ReflectionData for modifiable and performance-sensitive data.



4421 tmp = new ClassDesc[subclassNames.length];
4422 int i = 0;
4423 for (String subclassName : subclassNames) {
4424 try {
4425 tmp[i++] = ClassDesc.of(subclassName.replace('/', '.'));
4426 } catch (IllegalArgumentException iae) {
4427 throw new InternalError("Invalid type in permitted subclasses 
information: " + subclassName, iae);

4428 }
4429 }
Nit: rename tmp to some other name e.g. descs

I read the JVMS but it isn't clear to me that the VM will validate 
the names in `PermittedSubclasses`attribute are valid class 
descriptors.   I see ConstantPool::is_klass_or_reference check but 
can't find where it validates the name is a valid class descriptor - 
can you point me there?   (otherwise, maybe define it to be unspecified?)



W.r.t. the APIs. I don't want to delay this review.  I see that you 
renamed the method to new API style as I brought up.  OTOH,  I expect 
more discussion is needed.  Below is a recent comment from John on 
this topic [1]


One comment, really for the future, regarding the shape of the Java 
API here: It uses Optional and omits the "get" prefix on accessors. 
This is the New Style, as opposed to the Classic Style using null 
(for "empty" resu

RFR(XS): 8221306: JVMTI spec for FramePop(), MethodExit(), and MethodEnter() could use some cleanup

2020-05-31 Thread serguei.spit...@oracle.com

  
  
Please, review a fix for small spec bug:
    https://bugs.openjdk.java.net/browse/JDK-8221306
  
  Webrev:
   
http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/jvmt-funcs-cleanup.1/src/
  
  Updated JVM TI spec for the FramePop, MethodEntry and MethodExit events:
   
http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/jvmt-funcs-cleanup.1/docs/specs/jvmti.html#FramePop
  
  Summary:
    It is a minor spec cleanup for JVM TI events
  FramePop/MethodEntry/MethodExit:
     - added small clarification that GetFrameLocation needs to be
  asked for frame at depth 0
     - removed partly unneeded and partly incorrect statements about
  MethodExit event argument
  
  Testing:
    Manually verified the generated jvmti.html.
  
  I think, there is no need to file a CSR for this spec update as it
  is just minor cleanup.
  
  Thanks,
  Serguei

  



Re: RFR(XS): 8234882: JVM TI StopThread should only allow ThreadDeath

2020-05-31 Thread serguei.spit...@oracle.com

Hi David,

Also jumping to end.

On 5/30/20 06:50, David Holmes wrote:

Hi Serguei,

Jumping to the end for now ...

On 30/05/2020 5:50 am, serguei.spit...@oracle.com wrote:

Hi David and reviewers,

The updated webrev version is:
http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/jvmti-stop-thread.2/src/ 



This update adds testing that StopThread can return 
JVMTI_ERROR_INVALID_OBJECT error code.


The JVM TI StopThread spec is:
http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/jvmti-stop-thread.2/docs/specs/jvmti.html#StopThread 




There is a couple of comments below.


On 5/29/20 06:18, David Holmes wrote:

On 29/05/2020 6:24 pm, serguei.spit...@oracle.com wrote:

On 5/29/20 00:56, serguei.spit...@oracle.com wrote:

On 5/29/20 00:42, serguei.spit...@oracle.com wrote:

Hi David,

Thank you for reviewing this!

On 5/28/20 23:57, David Holmes wrote:

Hi Serguei,

On 28/05/2020 3:12 pm, serguei.spit...@oracle.com wrote:

Hi David,

I've updated the CSR and webrev in place.

The changes are:
  - addressed David's suggestion to rephrase StopThread 
description change
  - replaced JVMTI_ERROR_INVALID_OBJECT with 
JVMTI_ERROR_ILLEGAL_ARGUMENT
  - updated the implementation in jvmtiEnv.cpp to return 
JVMTI_ERROR_ILLEGAL_ARGUMENT
  - updated one of the nsk.jvmti StopThread tests to check 
error case with the JVMTI_ERROR_ILLEGAL_ARGUMENT



I'm reposting the links for convenience.

Enhancement:
https://bugs.openjdk.java.net/browse/JDK-8234882

CSR draft:
https://bugs.openjdk.java.net/browse/JDK-8245853


Spec updates are good - thanks.


Thank you for the CSR review.


Webrev:
http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/jvmti-stop-thread.1/src/ 



src/hotspot/share/prims/jvmtiEnv.cpp

The ThreadDeath check is fine but I'm a bit confused about the 
additional null check that leads to JVMTI_ERROR_INVALID_OBJECT. 
I can't see how resolve_external_guard can return NULL when not 
passed in NULL. Nor why that would result in 
JVMTI_ERROR_INVALID_OBJECT rather than JVMTI_ERROR_NULL_POINTER. 
And I note JVMTI_ERROR_NULL_POINTER is not even a listed error 
for StopThread! This part of the change seems unrelated to this 
issue.


I was also surprised with the JVMTI_ERROR_NULL_POINTER and 
JVMTI_ERROR_INVALID_OBJECT error codes.
The JVM TI spec automatic generation adds these two error codes 
for a jobject parameter.


Also, they both are from the Universal Errors section:
http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/jvmti-stop-thread.1/docs/specs/jvmti.html#universal-error 



You can find a link to this section at the start of the Error 
section:
http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/jvmti-stop-thread.1/docs/specs/jvmti.html#StopThread 



My understanding (not sure, it is right) is that NULL has to be 
reported with JVMTI_ERROR_NULL_POINTER and a bad
jobject (for instance, a WeakReference with a GC-ed target) has 
to be reported with JVMTI_ERROR_INVALID_OBJECT.
At least, I was not able to construct a test case to get this 
error code returned.
So, I'm puzzled with this. I'll try to find some examples with 
JVMTI_ERROR_NULL_POINTER errors.


Found the explanation.
The JDI file:
src/jdk.jdi/share/classes/com/sun/tools/jdi/JDWPException.java

has a fragment that translate the INVALID_OBJECT error to the 
ObjectCollectedException:

    RuntimeException toJDIException() {
    switch (errorCode) {
    case JDWP.Error.INVALID_OBJECT:
    return new ObjectCollectedException();

So, the INVALID_OBJECT is for a jobject handle that is referencing 
a collected object.
It means that previous implementation incorrectly returned 
JVMTI_ERROR_NULL_POINTER error code.


I should create and delete local or global ref to construct a test 
case for this.


Interesting that the JDWPException::toJDIException() does not 
convert the ILLEGAL_ARGUMENT error code to an 
IllegalArgumentException.

I've just added this conversion.


Given the definition of JDWP INVALID_OBJECT then obviously JDI 
converts it to ObjectCollectedException.


So reading further in JNI spec:

"Weak global references are a special kind of global reference. 
Unlike normal global references, a weak global reference allows the 
underlying Java object to be garbage collected. Weak global 
references may be used in any situation where global or local 
references are used."


So it seems that any function that takes a jobject cxould in fact 
accept a jweak, in which case JVMTI_ERROR_INVALID_OBJECT is a 
possibility in all cases. So IIUC JNIHandles::resolve_external_guard 
can return NULL if a weak reference has been collected. So the new 
code you propose seems correct.


You are right about weak global references.
I was able to construct a test case for JVMTI_ERROR_INVALID_OBJECT.
The JNI NewGlobalRef and DeleteGlobalRef are used for it.
You can find it in the updated webrev version.

However, this still is unrelated to the current issue and I do not 
see other JVM TI doing checks for this case. So this seems to be a 
much bro