RFR(10)(XS): JDK-8171365: nsk/jvmti/scenarios/events/EM04/em04t001: many errors for missed events

Chris Plummer chris.plummer at oracle.com
Tue Jun 6 02:48:33 UTC 2017


On 6/5/17 6:57 PM, Ioi Lam wrote:
>
>
> On 6/5/17 1:30 PM, Chris Plummer wrote:
>> On 6/5/17 8:56 AM, Ioi Lam wrote:
>>> Hi Chris,
>>>
>>>
>>> On 6/2/17 11:54 AM, Chris Plummer wrote:
>>>> Hello,
>>>>
>>>> [I'd like a compiler team member to comment on this, in addition to 
>>>> runtime or svc]
>>>>
>>>> Please review the following:
>>>>
>>>> https://bugs.openjdk.java.net/browse/JDK-8171365
>>>> http://cr.openjdk.java.net/~cjplummer/8171365/webrev.00/
>>>>
>>>> The CR is closed, so I'll describe the issue here:
>>>>
>>>> The test is making sure that all 
>>>> |JVMTI_EVENT_DYNAMIC_CODE_GENERATED| events that occur during the 
>>>> agent's OnLoad phase also occur when later GenerateEvents() is 
>>>> called. GenerateEvents() is generating some of the events, but most 
>>>> are not sent. The problem is CodeCache::blobs_do() is only 
>>>> iterating over NMethod code heaps, not all of the code heaps, so 
>>>> many code blobs are missed. I changed it to iterate over all the 
>>>> code heaps, and now all the 
>>>> |JVMTI_EVENT_DYNAMIC_CODE_GENERATED|events are sent.
>>>>
>>>> Note there is another version of CodeCache::blobs_do() that takes a 
>>>> closure object instead of a function pointer. It is used by GC and 
>>>> I assume is working properly by only iterating over NMethod code 
>>>> heaps, so I did not change it. The version that takes a function 
>>>> pointer is only used by JVMTI for implementing GenerateEvents(), so 
>>>> this change should not impact any other part of the VM. However, I 
>>>> do wonder if these blobs_do() methods should be renamed to avoid 
>>>> confusion since they don't (and haven't in the past) iterated over 
>>>> the same set of code blobs.
>>>>
>>> Yes, I think these two function would indeed be confusing. The 
>>> second variant also does a liveness check which is missing from the 
>>> first one:
>>>
>>>  621 void CodeCache::blobs_do(void f(CodeBlob* nm)) {
>>>  622   assert_locked_or_safepoint(CodeCache_lock);
>>>  623   FOR_ALL_HEAPS(heap) {
>>>  624     FOR_ALL_BLOBS(cb, *heap) {
>>>  625       f(cb);
>>>  626     }
>>>  627   }
>>>  628 }
>>>
>>>  664 void CodeCache::blobs_do(CodeBlobClosure* f) {
>>>  665   assert_locked_or_safepoint(CodeCache_lock);
>>>  666   FOR_ALL_NMETHOD_HEAPS(heap) {
>>>  667     FOR_ALL_BLOBS(cb, *heap) {
>>>  668       if (cb->is_alive()) {
>>>  669         f->do_code_blob(cb);
>>>  670 #ifdef ASSERT
>>>  671         if (cb->is_nmethod())
>>>  672         ((nmethod*)cb)->verify_scavenge_root_oops();
>>>  673 #endif //ASSERT
>>>  674       }
>>>  675     }
>>>  676   }
>>>  677 }
>>>
>>> The two function's APIs are equivalent, since CodeBlobClosure has a 
>>> single function, so I think it's better to stick with one API, i.e. 
>>> replace the function pointer with CodeBlobClosure
>>>
>>> class CodeBlobClosure : public Closure {
>>>  public:
>>>   // Called for each code blob.
>>>   virtual void do_code_blob(CodeBlob* cb) = 0;
>>> };
>>>
>>> For consistency, maybe we should change the first version to
>>>
>>> CodeCache::all_blobs_do(CodeBlobClosure* f)
>>>
>>> and the second to
>>>
>>> CodeCache::live_nmethod_blobs_do(CodeBlobClosure* f)
>>>
>>> Thanks
>>> - Ioi
>> Hi Ioi,
>>
>> Thanks for the review.
>>
>> I don't see a good reason why a closure should be used here. There's 
>> no state belonging to the iteration that needs to be accessed by the 
>> callback. It's just a simple functional callback, so it seems 
>> converting this to use a closure is overkill. I'd have to say the 
>> same is true of the closure version of do_blobs also. Why use a 
>> closure for that?
>>
> Some of the closures actually have instance fields. E.g.,
>
> class G1CodeBlobClosure : public CodeBlobClosure {
>   class HeapRegionGatheringOopClosure : public OopClosure {
>     ...
>   };
>
>   HeapRegionGatheringOopClosure _oc;
> ...
> };
Ok, I missed that. So at least some of the gc usage requires a closure. 
Not sure that's enough to make JVMTI switch over to it.
>
> I think in general using a closure is better than a function pointer. 
> It makes evolution of the code easier when in the future you need to 
> handle more complicated situations that would require states. Not sure 
> what the HotSpot convention is, but my preference would be to use 
> closures unless there's a strict performance requirement for using a 
> function pointer.
I guess I have the opposite thinking here. Unnecessary abstraction 
drives me batty, and I like to keep it simple unless there's clear 
future need for something more flexible. We have one call site in JVMTI 
for this method, and a new user ever did require a closure, JVMTI could 
be changed at that time.

I'll wait for the compiler team to chime in. I've already asked them to 
have a look (this issue not withstanding) because it is their code.

thanks,

Chris
>
>
> Thanks
> - Ioi
>
>
>> BTW, there also:
>>
>> void CodeCache::nmethods_do(void f(nmethod* nm)) {
>>   assert_locked_or_safepoint(CodeCache_lock);
>>   NMethodIterator iter;
>>   while(iter.next()) {
>>     f(iter.method());
>>   }
>> }
>>
>> So another functional version of a blob iterator. It's not real clear 
>> to me all the ways this differs from the closure version of 
>> blobs_do(), other than it allows you to provide an nmethod as a 
>> starting point for the iteration.
>>
>> Chris
>>>
>>>> thanks,
>>>>
>>>> Chris
>>>>
>>>> https://docs.oracle.com/javase/8/docs/platform/jvmti/jvmti.html#DynamicCodeGenerated 
>>>>
>>>
>>
>



More information about the hotspot-dev mailing list