RFR(m): 8220351: Cross-modifying code

Erik Österlund erik.osterlund at oracle.com
Mon Mar 18 11:30:59 UTC 2019


Hi,

Safely publishing JIT-compiled code is outside the scope of this patch, 
and a completely different can of worms. This patch only intends to make 
the code patching we do in HotSpot safer. To safely publish JIT-compiled 
code, some more effort will be required, and I think that discussion can 
wait. Just pretend it makes sense for now.

Thanks,
/Erik

On 2019-03-18 12:00, Robbin Ehn wrote:
>> Let's assume J2's modification makes it into J1's instruction stream. 
>> How is it
>> guaranteed that the new compiled code for methodB from the JIT makes 
>> it into
>> J1's instruction stream, too, if no serializing instruction is 
>> executed by J1?
>
> In short, no, there are no such guarantee AFAIK.
> If methodB is generate in memory with a valid instruction stream, we 
> may execute the old one.
> And J1 may see the unresolved call and also try to resolve it, seem 
> much more likely.
>
> ErikÖ have looked more into these cases. (I don't plan to address them 
> in this patch)
>
> /Robbin
>
>> My explanation was that the call instruction has the serializing 
>> effect, just
>> like in OPTION 1. Note as well the difference between OPTION 1 and 2: 
>> if the new
>> code is not reached by a jump then a serializing instruction is 
>> required as
>> well.
>>
>>    > That's the "accidental success" that is being avoided by this fix
>>
>> Which part of the fix would that be?
>>
>> Thanks, Richard.
>>
>> -----Original Message-----
>> From: David Holmes <david.holmes at oracle.com>
>> Sent: Montag, 18. März 2019 03:07
>> To: Reingruber, Richard <richard.reingruber at sap.com>; Robbin Ehn 
>> <robbin.ehn at oracle.com>; Doerr, Martin <martin.doerr at sap.com>; Andrew 
>> Haley <aph at redhat.com>; hotspot-dev at openjdk.java.net
>> Subject: Re: RFR(m): 8220351: Cross-modifying code
>>
>> On 15/03/2019 11:04 pm, Reingruber, Richard wrote:
>>>     > OPTION 1 is for self-modifying code, not cross-modifying code.
>>>
>>> I know. I wanted to point out that it seems to work for 
>>> cross-modifying code,
>>> too, in the sense that patchee java threads don't execute a 
>>> serializing instruction
>>> before jumping to compiled code or before executing a compiled call 
>>> another java
>>> thread just resolved.
>>
>> That's the "accidental success" that is being avoided by this fix. Today
>> it all seems to work just fine because the "distance" between the
>> actions of the patching thread and the patchee thread that wants to use
>> the new code is "vast".
>>
>> Cheers,
>> David
>>
>>> Cheers, Richard.
>>>
>>> -----Original Message-----
>>> From: David Holmes <david.holmes at oracle.com>
>>> Sent: Freitag, 15. März 2019 12:55
>>> To: Reingruber, Richard <richard.reingruber at sap.com>; Robbin Ehn 
>>> <robbin.ehn at oracle.com>; Doerr, Martin <martin.doerr at sap.com>; 
>>> Andrew Haley <aph at redhat.com>; hotspot-dev at openjdk.java.net
>>> Subject: Re: RFR(m): 8220351: Cross-modifying code
>>>
>>> On 15/03/2019 9:08 pm, Reingruber, Richard wrote:
>>>> Hi Robbin,
>>>>
>>>> I'm referring to x86 here.
>>>>
>>>> My comment/question about the requirement of an ICache invalidation 
>>>> in the
>>>> patcher thread was a little "undereducated". After reading recent 
>>>> manuals [1]:
>>>>
>>>>      1. I think your right that a serializing instruction after the 
>>>> safepoint poll
>>>>         is necessary.
>>>>
>>>>      2. I doubt that cache flushing is required at all, according 
>>>> to [1]. At least
>>>>         SPECjvm2008 runs with an AbstractICache::_flush_icache_stub 
>>>> that
>>>>         immediately returns.
>>>>
>>>> In the sense of [1] JIT compilers and JIT runtimes are 
>>>> cross-modifying code,
>>>> too, when they compile bytecode and resolve compiled calls. But 
>>>> afaik the java
>>>> threads don't execute a serializing instruction before executing 
>>>> that code. So,
>>>> if I'm not mistaken, (* OPTION 1 *) of [1] where the patchee 
>>>> threads jump to the
>>>> modified code is legal as well.
>>>
>>> OPTION 1 is for self-modifying code, not cross-modifying code.
>>>
>>> David
>>> -----
>>>
>>>> So at least theoretically you should be able to replace the 
>>>> serializing
>>>> instruction with a call to an address you would load from the 
>>>> thread. The
>>>> address should lead to the runtime, where the thread would block if 
>>>> the
>>>> safepoint is still active or just return if it is not.
>>>>
>>>> The last point was rather exploring the space of legal solutions 
>>>> than a
>>>> suggestion to solve the issue. I'd favor your approach if you 
>>>> manage to do the
>>>> serialization conditionally (BTW: a mechanism similar to 
>>>> JavaThread::*deopt_suspend*
>>>> would be yet another way to do that).
>>>>
>>>> Cheers, Richard.
>>>>
>>>> [1] 8.1.3 Handling Self- and Cross-Modifying Code
>>>>        in Intel(R) 64 and IA-32 ArchitecturesSoftware Developer's 
>>>> Manual. Volume 3
>>>>        (3A, 3B, 3C & 3D): System Programming Guide
>>>> https://software.intel.com/sites/default/files/managed/a4/60/325384-sdm-vol-3abcd.pdf
>>>>        on https://software.intel.com/en-us/articles/intel-sdm
>>>>
>>>> -----Original Message-----
>>>> From: Robbin Ehn <robbin.ehn at oracle.com>
>>>> Sent: Donnerstag, 14. März 2019 13:24
>>>> To: Reingruber, Richard <richard.reingruber at sap.com>; Doerr, Martin 
>>>> <martin.doerr at sap.com>; David Holmes <david.holmes at oracle.com>; 
>>>> hotspot-dev at openjdk.java.net
>>>> Subject: Re: RFR(m): 8220351: Cross-modifying code
>>>>
>>>> Hi Richard,
>>>>
>>>> On 3/14/19 11:12 AM, Reingruber, Richard wrote:
>>>>> Hi Robbin,
>>>>>
>>>>>       > the reason I heard for not doing invalidate_range/word in 
>>>>> nmethod::oops_do
>>>>>       > is that it was deemed that a safepoint is 'long enough'.
>>>>>
>>>>> This doesn't seem to be a very good reason. I did a little 
>>>>> modification to your
>>>>> initial figure:
>>>>
>>>> That's why we are adding the instruction barrier!
>>>>
>>>>>
>>>>> JavaThread:             | VMThread
>>>>> StoreLoad               |
>>>>>                             | update <immediate oop>
>>>>>                             | ? Global ICache Invalidate ?
>>>>>                             | disarm
>>>>> load thread_poll        |
>>>>>
>>>>> Question would be: does an ICache flush happen after the immediate 
>>>>> oop update?
>>>>> I would consider it problematic if not. Even if the safepoint was 
>>>>> very long.
>>>>
>>>> The icache flush assumes it can stop speculation and flush 
>>>> instruction cache in
>>>> patchee thread.
>>>> Correct me if anything is wrong:
>>>> - sparc needs flush <adr> in all patchee threads.
>>>> - arm/aarch64 needs isb + ___clear_cache(adr,..) in all patchee 
>>>> threads.
>>>> - ppc needs isync in all patchee threads?
>>>> - s390 needs zarch_sync all in patchee threads?
>>>> - x86 needs cpuid in all in patchee threads.
>>>>
>>>> So a "Global ICache Invalidate" done by patcher thread (VMThread in 
>>>> this case)
>>>> have no effect in patchee threads!?
>>>>
>>>> Adding a few words on x86 ICache::Invalidate/word.
>>>> We have TSO, so if the patchee thread can see poll is disarmed all 
>>>> other stores
>>>> are visible. I have seen no case ICache::Invalidate/word would make 
>>>> a difference
>>>> from a StoreStore/compiler barrier (still talking about platform 
>>>> code for x86) ?
>>>> The problem is if we prefect an instruction over the load of the poll.
>>>> If poll is disarmed this perfected instruction can be fully executed.
>>>> If that happens to contain an immediate oop, we don't know if it's 
>>>> the patched
>>>> oop or not.
>>>>
>>>> /Robbin
>>>>
>>>>>
>>>>> Cheers Richard.
>>>>>
>>>>> -----Original Message-----
>>>>> From: Robbin Ehn <robbin.ehn at oracle.com>
>>>>> Sent: Donnerstag, 14. März 2019 10:34
>>>>> To: Doerr, Martin <martin.doerr at sap.com>; David Holmes 
>>>>> <david.holmes at oracle.com>; hotspot-dev at openjdk.java.net
>>>>> Cc: Reingruber, Richard <richard.reingruber at sap.com>
>>>>> Subject: Re: RFR(m): 8220351: Cross-modifying code
>>>>>
>>>>> Hi Martin,
>>>>>
>>>>> On 3/14/19 10:25 AM, Doerr, Martin wrote:
>>>>>> Hi Robbin,
>>>>>>
>>>>>>> But that is whole new subject and let's keep that separate from 
>>>>>>> this :)
>>>>>> Sure, we can keep the modification side discussion separate. This 
>>>>>> change is already difficult enough ��
>>>>>>
>>>>>>
>>>>>> Btw. I haven't sent the ppc/s390 instruction cache barriers. Here 
>>>>>> they are:
>>>>>>
>>>>>> orderAccess_aix/linux_ppc.hpp:
>>>>>> inline void OrderAccess::instruction_pipeline() { inlasm_isync(); }
>>>>>>
>>>>>> orderAccess_linux_s390.hpp:
>>>>>> inline void OrderAccess::instruction_pipeline() { 
>>>>>> inlasm_zarch_sync(); }
>>>>>>
>>>>>
>>>>> Thanks!
>>>>>
>>>>>>> nmethod::oops_do calls the closure f->do_oop(r->oop_addr()) for 
>>>>>>> oops encoded into the instruction stream.
>>>>>>> I couldn't find a call to AbstractICache::invalidate_range.
>>>>>
>>>>> I think I miss-understood you here, the reason I heard for not doing
>>>>> invalidate_range/word in nmethod::oops_do is that it was deemed 
>>>>> that a
>>>>> safepoint is 'long enough'.
>>>>>
>>>>> /Robbin
>>>>>
>>>>>>
>>>>>> Look for ICache::invalidate_range, I see 11 calls on x64.
>>>>>> And one call to AbstractICache/ICache::invalidate_word.
>>>>>> Btw I have spent some time looking at x86/icache_x86.cpp...
>>>>>> But that is whole new subject and let's keep that separate from 
>>>>>> this :)
>>>>>>
>>>>>> I'll create issues for some of these topics, which if nothing 
>>>>>> else should be
>>>>>> discussed.
>>>>>>
>>>>>> /Robbin
>>>>>>
>>>>>>>
>>>>>>> Does anybody know where it is or if it's missing?
>>>>>>>
>>>>>>> Best regards,
>>>>>>> Martin
>>>>>>>



More information about the hotspot-dev mailing list